﻿#region Copyright 
/*-------------------------------------------------------------------------
* 命名空间名称/文件名:    SSPivot.Admin.Core.Service.sys.Dict/SysDictServiceImpl 
* CLR版本:     4.0.30319.42000
* 机器名称:    DESKTOP-NHMLO8A
* 功 能：       N/A
* 类 名：       SysDictServiceImpl
* 创建时间：  2025/6/4 15:12:12
* 版本号：      v1.0
* 创建人:        xulong
*-------------------------------------------------------------------------*/
#endregion
using MapsterMapper;
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc;
using SSPivot.Admin.Core.DbModel.sys;
using SSPivot.Admin.Core.Service.Dto;
using SSPivot.Admin.Core.Service.sys.Dict.Dto;
using SSPivot.AspNetCore.Services;
using SSPivot.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using SSPivot.Admin.Core.Repository;
using SSPivot.Tools;
using Mapster;
using Magicodes.ExporterAndImporter.Core.Models;
using Microsoft.EntityFrameworkCore;

namespace SSPivot.Admin.Core.Service.sys.Dict
{
    /// <summary>
    /// 数据字典服务
    /// </summary>
    public class SysDictServiceImpl : ApplicationService, ISysDictService
    {
        #region 接口注入
        public ISSPivotRepository<sys_dict_type> DictTypeRepository { get; set; }
        public ISSPivotRepository<sys_dict> DictRepository { get; set; }
        public IEHelper IEHelper { get; set; }
        public SysDictServiceImpl(ISSPivotRepository<sys_dict_type> typeRepository,
            ISSPivotRepository<sys_dict> dictRepository,
            IEHelper helper)
        {
            DictTypeRepository = typeRepository;
            DictRepository = dictRepository;
            IEHelper = helper;
        }
        #endregion
        #region 服务

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<SysDictDto> GetAsync(long id)
        {
            var result = await DictRepository.GetAsync(id);
            return result.Adapt<SysDictDto>();
        }
        /// <summary>
        /// 获取数量 
        /// </summary>
        /// <returns></returns>
        public async Task<int> CountAsync(QuerySysDictRequest model)
        {
            return await DictRepository.QueryNoTracking(this.BuildSearch(model)).CountAsync();
        }
        /// <summary>
        /// 是否存在 
        /// </summary>
        /// <returns></returns>
        public async Task<bool> AnyAsync(QuerySysDictRequest model)
        {
            return await DictRepository.QueryNoTracking(this.BuildSearch(model)).AnyAsync();
        }
        /// <summary>
        /// 查询列表
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<List<SysDictTypeDto>> QueryAsync(QuerySysDictRequest model)
        {
            var data = await DictRepository.QueryNoTracking(this.BuildSearch(model), this.BuildSort(model)).ToListAsync();
            if (data == null) return null;
            return data.Adapt<List<SysDictTypeDto>>();
        }

        /// <summary>
        /// 查询分页
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>       
        public async Task<(List<SysDictTypeDto>,PageResult)> PageAsync(QuerySysDictRequest model, PageResult page)
        {
            var data = await DictRepository.QueryNoTracking(this.BuildSearch(model), this.BuildSort(model), page).ToListAsync();
            if (data == null) return (null, page);
            return (data.Adapt<List<SysDictTypeDto>>(), page);
        }


        /// <summary>
        /// 通过类型编码查询列表
        /// </summary>
        /// <param name="codes">字典类型编码列表</param>
        /// <returns></returns>

        public async Task<Dictionary<string, List<SysDictListDto>>> GetListAsync(string[] codes)
        {
            var query = this.BuildSearch(new QuerySysDictRequest() { Codes = codes });
            query = query.And(e => e.DictType.Enabled == true && e.Enabled == true);
            var list = await DictRepository.Query(query).OrderBy(e => e.Sort)
                .Select(e => new SysDictListDto
                {
                    Id = e.Id,
                    Code = e.Code,
                    DictTypeCode = e.DictType.Code,
                    DictTypeName = e.DictType.Name,
                    Name = e.Name,
                    Value = e.Value,
                }).ToListAsync();


            var dicts = new Dictionary<string, List<SysDictListDto>>();
            foreach (var code in codes)
            {
                if (code.IsNotNullOrEmpty())
                    dicts[code] = list.Where(a => a.DictTypeCode == code).ToList();
            }
            return dicts;
        }

        /// <summary>
        /// 通过类型名称查询列表
        /// </summary>
        /// <param name="names">字典类型名称列表</param>
        /// <returns></returns>

        public async Task<Dictionary<string, List<SysDictListDto>>> GetListByNamesAsync(string[] names)
        {
            var query = this.BuildSearch(new QuerySysDictRequest() { Names = names });
            query = query.And(e => e.DictType.Enabled == true && e.Enabled == true);
            var list = await DictRepository.Query(query).OrderBy(e => e.Sort)
                .Select(e => new SysDictListDto
                {
                    Id = e.Id,
                    Code = e.Code,
                    DictTypeCode = e.DictType.Code,
                    DictTypeName = e.DictType.Name,
                    Name = e.Name,
                    Value = e.Value,
                }).ToListAsync();

            var dicts = new Dictionary<string, List<SysDictListDto>>();
            foreach (var name in names)
            {
                if (name.IsNotNullOrEmpty())
                    dicts[name] = list.Where(a => a.DictTypeName == name).ToList();
            }

            return dicts;
        }

        /// <summary>
        /// 下载导入模板
        /// </summary>
        /// <returns></returns>

        public async Task<ActionResult> DownloadTemplateAsync()
        {
            var fileName = $"数据字典模板{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";
            return await IEHelper.DownloadTemplateAsync(new DictImport(), fileName);
        }

        /// <summary>
        /// 下载错误标记文件
        /// </summary>
        /// <param name="fileId"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>

        public async Task<ActionResult> DownloadErrorMarkAsync(string fileId, string fileName)
        {
            if (fileName.IsNull())
            {
                fileName = $"数据字典错误标记{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";
            }
            return await IEHelper.DownloadErrorMarkAsync(fileId, fileName);
        }

        /// <summary>
        /// 导出数据
        /// </summary>
        /// <returns></returns>

        public async Task<ActionResult> ExportDataAsync(ExportInput input)
        {
            var orderBy = new Dictionary<Expression<Func<sys_dict, dynamic>>, SortType>();
            orderBy.Add(e => e.DictType.Sort, SortType.Asc);
            orderBy.Add(e => e.Sort, SortType.Asc);
            orderBy.Add(e => e.Id, SortType.Desc);

            var dataList = await DictRepository.Query().SortBy(orderBy).Select(e => new DictExport
            {
                DictTypeName = e.DictType.Name
            }).ToListAsync();

            var dictTypeName = dataList.Count > 0 ? dataList[0].DictTypeName : string.Empty;

            //导出数据
            var fileName = input.FileName.IsNullOrEmpty() ? input.FileName : $"数据字典-{dictTypeName}列表{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";

            return await IEHelper.ExportDataAsync(dataList, fileName, dictTypeName);
        }

        /// <summary>
        /// 导入数据
        /// </summary>
        /// <param name="file"></param>
        /// <param name="duplicateAction"></param>
        /// <param name="fileId"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<ImportOutput> ImportDataAsync([Required] IFormFile file, int duplicateAction, string fileId)
        {
            var importResult = await IEHelper.ImportDataAsync<DictImport>(file, fileId, async (importResult) =>
            {
                //检查数据
                var importDataList = importResult.Data;
                var importDictTypeNameList = importDataList.Select(a => a.DictTypeName).Distinct().ToList();
                var dictTypeList = await DictTypeRepository.Query(e => importDictTypeNameList.Contains(e.Name)).Select(e => new
                {
                    Id = e.Id,
                    Name = e.Name
                }).ToListAsync();

                var dictTypeIdList = dictTypeList.Select(a => a.Id).Distinct().ToList();

                var dictList = await DictRepository.Query(a => dictTypeIdList.Contains(a.DictTypeId)).Select(a => new { a.Id, a.DictTypeId, a.Name, a.Code, a.Value }).ToListAsync();

                if (importResult.RowErrors == null)
                {
                    importResult.RowErrors = new List<DataRowErrorInfo>();
                }
                var errorList = importResult.RowErrors;

                foreach (var importData in importDataList)
                {
                    var rowIndex = importDataList.ToList().FindIndex(o => o.Equals(importData)) + 2;
                    importData.DictTypeId = dictTypeList.Where(a => a.Name == importData.DictTypeName).Select(a => a.Id).FirstOrDefault();

                    if (importData.DictTypeId > 0)
                    {
                        importData.Id = dictList.Where(a => a.DictTypeId == importData.DictTypeId && a.Name == importData.Name).Select(a => a.Id).FirstOrDefault();

                        if (importData.Id > 0)
                        {
                            if (duplicateAction == 1)
                            {
                                if (importData.Code.IsNotNullOrEmpty() && dictList.Where(a => a.Id != importData.Id && a.DictTypeId == importData.DictTypeId && a.Code == importData.Code).Any())
                                {
                                    var errorInfo = new DataRowErrorInfo()
                                    {
                                        RowIndex = rowIndex,
                                    };
                                    errorInfo.FieldErrors.Add("字典编码", importData.Code + "已存在");
                                    errorList.Add(errorInfo);
                                }

                                if (importData.Value.IsNotNullOrEmpty() && dictList.Where(a => a.Id != importData.Id && a.DictTypeId == importData.DictTypeId && a.Value == importData.Value).Any())
                                {
                                    var errorInfo = new DataRowErrorInfo()
                                    {
                                        RowIndex = rowIndex,
                                    };
                                    errorInfo.FieldErrors.Add("字典值", importData.Value + "已存在");
                                    errorList.Add(errorInfo);
                                }
                            }
                        }
                        else
                        {
                            if (importData.Code.IsNotNullOrEmpty() && dictList.Where(a => a.DictTypeId == importData.DictTypeId && a.Code == importData.Code).Any())
                            {
                                var errorInfo = new DataRowErrorInfo()
                                {
                                    RowIndex = rowIndex,
                                };
                                errorInfo.FieldErrors.Add("字典编码", importData.Code + "已存在");
                                errorList.Add(errorInfo);
                            }

                            if (importData.Value.IsNotNullOrEmpty() && dictList.Where(a => a.DictTypeId == importData.DictTypeId && a.Value == importData.Value).Any())
                            {
                                var errorInfo = new DataRowErrorInfo()
                                {
                                    RowIndex = rowIndex,
                                };
                                errorInfo.FieldErrors.Add("字典值", importData.Value + "已存在");
                                errorList.Add(errorInfo);
                            }
                        }
                    }
                    else
                    {
                        var errorInfo = new DataRowErrorInfo()
                        {
                            RowIndex = rowIndex,
                        };
                        errorInfo.FieldErrors.Add("字典分类", importData.DictTypeName + "不存在");
                        errorList.Add(errorInfo);
                    }
                }

                return importResult;
            });

            var importDataList = importResult.Data;
            var output = new ImportOutput()
            {
                Total = importDataList.Count
            };
            if (output.Total > 0)
            {
                //新增
                var insetImportDataList = importDataList.Where(a => a.Id == 0).ToList();

                var insetDataList = new List<sys_dict>();
                foreach (var item in insetImportDataList)
                {
                    insetDataList.Add(await DictRepository.AddAsync(item.Adapt<sys_dict>()));
                }

                //修改
                var updateImportDataList = importDataList.Where(a => a.Id > 0).ToList();
                if (duplicateAction == 1 && updateImportDataList?.Count > 0)
                {
                    var updateImportDataIds = updateImportDataList.Select(e => e.Id).ToList();
                    var dbDataList = await DictRepository.Query(a => updateImportDataIds.Contains(a.Id)).ToListAsync();
                    foreach (var dbData in dbDataList)
                    {
                        var data = updateImportDataList.Where(a => a.Id == dbData.Id).First();
                        data.Adapt(dbData);
                    }
                    output.UpdateCount = updateImportDataList.Count;
                    DictRepository.DbContext.BulkUpdate(dbDataList);
                }
            }

            return output;
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<long> AddAsync(SysDictDto input)
        {
            if (await DictRepository.QueryNoTracking(a => a.DictTypeId == input.DictTypeId && a.Name == input.Name).AnyAsync())
            {
                throw ServiceResult.Exception("字典已存在");
            }

            if (input.Code.IsNotNullOrEmpty() && await DictRepository.QueryNoTracking(a => a.DictTypeId == input.DictTypeId && a.Code == input.Code).AnyAsync())
            {
                throw ServiceResult.Exception("字典编码已存在");
            }

            if (input.Value.IsNotNullOrEmpty() && await DictRepository.QueryNoTracking(a => a.DictTypeId == input.DictTypeId && a.Value == input.Value).AnyAsync())
            {
                throw ServiceResult.Exception("字典值已存在");
            }

            var entity = Mapper.Map<sys_dict>(input);
            if (entity.Sort == 0)
            {
                var sort = await DictRepository.QueryNoTracking(a => a.DictTypeId == input.DictTypeId).MaxAsync(a => a.Sort);
                entity.Sort = sort + 1;
            }
            await DictRepository.AddAsync(entity);
            return entity.Id;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task UpdateAsync(SysDictDto input)
        {
            var entity = await DictRepository.GetAsync(input.Id);
            if (!(entity?.Id > 0))
            {
                throw ServiceResult.Exception("字典不存在");
            }

            if (await DictRepository.QueryNoTracking(a => a.Id != input.Id && a.DictTypeId == input.DictTypeId && a.Name == input.Name).AnyAsync())
            {
                throw ServiceResult.Exception("字典已存在");
            }

            if (input.Code.IsNotNullOrEmpty() && await DictRepository.QueryNoTracking(a => a.Id != input.Id && a.DictTypeId == input.DictTypeId && a.Code == input.Code).AnyAsync())
            {
                throw ServiceResult.Exception("字典编码已存在");
            }

            if (input.Value.IsNotNullOrEmpty() && await DictRepository.QueryNoTracking(a => a.Id != input.Id && a.DictTypeId == input.DictTypeId && a.Value == input.Value).AnyAsync())
            {
                throw ServiceResult.Exception("字典值已存在");
            }

            Mapper.Map(input, entity);
            await DictRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 彻底删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteAsync(long id)
        {
            await DictRepository.QueryIgnoreQueryFilters(e => e.Id == id).ExecuteDeleteAsync();
        }

        /// <summary>
        /// 批量彻底删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task BatchDeleteAsync(long[] ids)
        {
            await DictRepository.QueryIgnoreQueryFilters(e => ids.Contains(e.Id)).ExecuteDeleteAsync();
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task SoftDeleteAsync(long id)
        {
            await DictRepository.DeleteAsync(id);
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task BatchSoftDeleteAsync(long[] ids)
        {
            await DictRepository.Query(e => ids.Contains(e.Id)).ExecuteDeleteAsync();
        }
        #endregion
        #region private
        private Expression<Func<sys_dict, bool>> BuildSearch(QuerySysDictRequest model)
        {
            Expression<Func<sys_dict, bool>> whereCondition = e => true;

            if (model.Key.IsNotNullOrWhiteSpace())
                whereCondition = whereCondition.And(e => e.Name.Contains(model.Key) || e.Code.Contains(model.Key));
            if (model.DictTypeId.HasValue)
                whereCondition = whereCondition.And(x => x.DictTypeId == model.DictTypeId);
            if (model.Codes != null && model.Codes.Length > 0)
                whereCondition = whereCondition.And(e => model.Codes.Contains(e.DictType.Code));
            if (model.Names != null && model.Names.Length > 0)
                whereCondition = whereCondition.And(e => model.Names.Contains(e.DictType.Name));
            return whereCondition;
        }

        private Dictionary<Expression<Func<sys_dict, dynamic>>, SortType> BuildSort(QuerySysDictRequest model)
        {
            var orderBy = new Dictionary<Expression<Func<sys_dict, dynamic>>, SortType>();

            orderBy.Add(e => e.Sort, SortType.Asc);
            orderBy.Add(e => e.Id, SortType.Desc);
            return orderBy;
        }

        #endregion
    }
}
